#include<iostream>
#include<fstream>
#include<sys/stat.h>
#include"../src/server.hpp"

size_t Split(const std::string &src, const std::string &sep, std::vector<std::string> *arry)
{
    size_t offset = 0;
    while (offset < src.size())
    {
        size_t pos = src.find(sep, offset); // 在src字符串的偏移量offset处，开始向后sep字符！
        std::string sub = src.substr(offset, pos - offset);
        if (pos == std::string::npos) // 没有找到特定字符！
        {
            arry->push_back(src.substr(offset)); // 将剩下的都当做子串！
            return arry->size();
        }
        if(sub.size() > 0)//防止aaaa,,,,,,,bbb
            arry->push_back(sub);
        offset = pos + sep.size();
    }
    return arry->size();
}

static bool ReadFile(const std::string filename, std::string &buf)
{

    std::ifstream ifs(filename, std::ios::binary);
    if (ifs.is_open() == false)
    {
        ERR_LOG("OPEN FILe :%s FAILED!", filename.c_str());
        return false;
    }
    // 先获取文件大小！——将文件偏移到末尾减去起始位置就是文件大小！
    size_t fsize = 0;
    ifs.seekg(0, ifs.end); // 从末尾位置开始，偏移0位
    fsize = ifs.tellg();   // 获取
    ifs.seekg(0, ifs.beg); // 跳转回文件的起始地址！

    buf.resize(fsize);
    ifs.read(&buf[0], fsize);
    if (ifs.good() == false) // 表示上一个操作有没有出现问题！
    {
        ERR_LOG("READ %s FILE FAILED!", filename.c_str());
        ifs.close();
        return false;
    }
    ifs.close();
    return true;
}
static bool WriteFile(const std::string filename,const std::string &buf)
{
   std::ofstream ofs(filename,std::ios::binary|std::ios::trunc); //打开文件后将文件清空！
   if(ofs.is_open() == false)
   {
       ERR_LOG("OPEN FILe :%s FAILED!", filename.c_str());
       return false;
   }
   ofs.write(buf.c_str(),buf.size());
   if(ofs.good() == false)
   {
        ERR_LOG("WRITE %s FILE FAILED!");
        ofs.close();
        return false;
   }
   ofs.close();
   return true;
}

static std::string UrlEncode(const std::string url, bool convert_space_to_plus) // 第二个参数就是是否将空格转化为加号
{
    std::string res;
    for (auto &c : url)
    { // sialnum函数判断是不是数字字符和大小写字母！
        if (c == '.' || c == '~' || c == '_' || c == '-' || isalnum(c)!= 0) 
        {
            res += c;
            continue;
        }
        if (c == ' ' && convert_space_to_plus == true)
        {
            res += '+';
            continue;
        }
        // 剩下的字符都是需要编码为%HH格式的
        char tmp[4] = {0};
        snprintf(tmp, 4, "%%%02X", c); //%% 是用来输入正常的% %02X——大写16进制输入！02是用来当做占位符
        res += tmp;
    }
    return res;
}
static char HEXTOI(char c)
{
    if (c >= '0' && c <= '9')
        return c - '0';
    else if (c >= 'a' && c <= 'z')
        return c - 'a'+10;//a是10，b是11在16进制中！所以我们要加上10！
    else if (c >= 'A' && c <= 'Z')
        return c - 'A'+10;//A是10，B是11在16进制中！所以我们要加上10！

    return -1;
}

    //URL解码
static std::string UrlDecode(const std::string url, bool convert_space_to_plus) // 第二个参数就是是否将空格转化为加号
{
    // 遇到%将紧随其后的两个字符转换为数字！——第一个数字左移4位，然后加上第二个数字
    // 例如：+ ——> %2b 转换回来就是 2<<4 + b ,<< 4就是相当于*16
    std::string res;
    for (int i = 0; i < url.size(); i++)
    {
        if (url[i] == '%') // 遇到%才进行解码
        {
            char v1 = HEXTOI(url[i + 1]);
            char v2 = HEXTOI(url[i + 2]);
            char v = (v1 << 4) + v2;
            res += v;
            i += 2;
            continue;
        }
        if (url[i] == '+' && convert_space_to_plus == true)
        {
            res += ' ';
            continue;
        }
        res += url[i]; // 没有遇到就正常进行！
    }
    return res;
}
static std::string StatusDesc(int status)
{
    std::unordered_map<int,std::string> status_msg{
        {100, "Continue"},
            {101, "Switching Protocol"},
            {102, "Processing"},
            {103, "Early Hints"},
            {200, "OK"},
            {201, "Created"},
            {202, "Accepted"},
            {203, "Non-Authoritative Information"},
            {204, "No Content"},
            {205, "Reset Content"},
            {206, "Partial Content"},
            {207, "Multi-Status"},
            {208, "Already Reported"},
            {226, "IM Used"},
            {300, "Multiple Choice"},
            {301, "Moved Permanently"},
            {302, "Found"},
            {303, "See Other"},
            {304, "Not Modified"},
            {305, "Use Proxy"},
            {306, "unused"},
            {307, "Temporary Redirect"},
            {308, "Permanent Redirect"},
            {400, "Bad Request"},
            {401, "Unauthorized"},
            {402, "Payment Required"},
            {403, "Forbidden"},
            {404, "Not Found"},
            {405, "Method Not Allowed"},
            {406, "Not Acceptable"},
            {407, "Proxy Authentication Required"},
            {408, "Request Timeout"},
            {409, "Conflict"},
            {410, "Gone"},
            {411, "Length Required"},
            {412, "Precondition Failed"},
            {413, "Payload Too Large"},
            {414, "URI Too Long"},
            {415, "Unsupported Media Type"},
            {416, "Range Not Satisfiable"},
            {417, "Expectation Failed"},
            {418, "I'm a teapot"},
            {421, "Misdirected Request"},
            {422, "Unprocessable Entity"},
            {423, "Locked"},
            {424, "Failed Dependency"},
            {425, "Too Early"},
            {426, "Upgrade Required"},
            {428, "Precondition Required"},
            {429, "Too Many Requests"},
            {431, "Request Header Fields Too Large"},
            {451, "Unavailable For Legal Reasons"},
            {501, "Not Implemented"},
            {502, "Bad Gateway"},
            {503, "Service Unavailable"},
            {504, "Gateway Timeout"},
            {505, "HTTP Version Not Supported"},
            {506, "Variant Also Negotiates"},
            {507, "Insufficient Storage"},
            {508, "Loop Detected"},
            {510, "Not Extended"},
            {511, "Network Authentication Required"}
    };
    auto it = status_msg.find(status);
    if(it != status_msg.end())
        return it->second;
    return "UnKnow";
}

static std::string ExMime(const std::string filename)
{
    std::unordered_map<std::string, std::string> mime_msg{

        {".aac", "audio/aac"},
        {".abw", "application/x-abiword"},
        {".arc", "application/x-freearc"},
        {".avi", "video/x-msvideo"},
        {".azw", "application/vnd.amazon.ebook"},
        {".bin", "application/octet-stream"},
        {".bmp", "image/bmp"},
        {".bz", "application/x-bzip"},
        {".bz2", "application/x-bzip2"},
        {".csh", "application/x-csh"},
        {".css", "text/css"},
        {".csv", "text/csv"},
        {".doc", "application/msword"},
        {".docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"},
        {".eot", "application/vnd.ms-fontobject"},
        {".epub", "application/epub+zip"},
        {".gif", "image/gif"},
        {".htm", "text/html"},
        {".html", "text/html"},
        {".ico", "image/vnd.microsoft.icon"},
        {".ics", "text/calendar"},
        {".jar", "application/java-archive"},
        {".jpeg", "image/jpeg"},
        {".jpg", "image/jpeg"},
        {".js", "text/javascript"},
        {".json", "application/json"},
        {".jsonld", "application/ld+json"},
        {".mid", "audio/midi"},
        {".midi", "audio/x-midi"},
        {".mjs", "text/javascript"},
        {".mp3", "audio/mpeg"},
        {".mpeg", "video/mpeg"},
        {".mpkg", "application/vnd.apple.installer+xml"},
        {".odp", "application/vnd.oasis.opendocument.presentation"},
        {".ods", "application/vnd.oasis.opendocument.spreadsheet"},
        {".odt", "application/vnd.oasis.opendocument.text"},
        {".oga", "audio/ogg"},
        {".ogv", "video/ogg"},
        {".ogx", "application/ogg"},
        {".otf", "font/otf"},
        {".png", "image/png"},
        {".pdf", "application/pdf"},
        {".ppt", "application/vnd.ms-powerpoint"},
        {".pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation"},
        {".rar", "application/x-rar-compressed"},
        {".rtf", "application/rtf"},
        {".sh", "application/x-sh"},
        {".svg", "image/svg+xml"},
        {".swf", "application/x-shockwave-flash"},
        {".tar", "application/x-tar"},
        {".tif", "image/tiff"},
        {".tiff", "image/tiff"},
        {".ttf", "font/ttf"},
        {".txt", "text/plain"},
        {".vsd", "application/vnd.visio"},
        {".wav", "audio/wav"},
        {".weba", "audio/webm"},
        {".webm", "video/webm"},
        {".webp", "image/webp"},
        {".woff", "font/woff"},
        {".woff2", "font/woff2"},
        {".xhtml", "application/xhtml+xml"},
        {".xls", "application/vnd.ms-excel"},
        {".xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"},
        {".xml", "application/xml"},
        {".xul", "application/vnd.mozilla.xul+xml"},
        {".zip", "application/zip"},
        {".3gp", "video/3gpp"},
        {".3g2", "video/3gpp2"},
        {".7z", "application/x-7z-compressed"}};
    // 例如：a.b.txt最后一个点的后面就是后缀！
    size_t pos = filename.find_last_of('.');
    if (pos == std::string::npos)
        return "application/octet-stream"; // 没有找到就返回文件类型是一个二进制流！

    std::string ext = filename.substr(pos);
    auto it = mime_msg.find(ext);
    if (it == mime_msg.end())
        return "application/octet-stream"; // 没有找到就返回文件类型是一个二进制流！

    return it->second;
}

static bool IsDirectory(const std::string filename)
{
    struct stat st;
    int ret = stat(filename.c_str(),&st);
    if(ret < 0)
    {
        return false;
    }
    return S_ISDIR(st.st_mode);//这个是一个宏！可以用来帮我们判断是不是一个文件夹！
}

//判断文件是不是一个普通文件！
static bool IsRegular(const std::string filename)
{
    struct stat st;
    int ret = stat(filename.c_str(),&st);
    if(ret < 0)
    {
        return false;
    }
    return S_ISREG(st.st_mode);//这个是一个宏！可以用来帮我们判断是不是一个文件夹！
}

static bool ValidPath(const std::string &path)
{
    // 判断思想计算目录深度！以/作为间隔！来进行字符串的分割！
    // 来判断有多少子目录！那么就有多少层！
    // 深度是不能小于0的！
    std::vector<std::string> substr;
    Split(path, "/", &substr);
    int level = 0;
    for (auto &dir : substr)
    {
        if (dir == "..")
        {
            --level; // 任意一层走出相对根目录就说明有问题！
            if (level < 0)
                return false;
            continue;
        }
        ++level;
    }
    return true;
}

int main()
{
    // std::cout <<ValidPath("/index.html") << std::endl;
    // std::cout <<ValidPath("html/../../index.html") << std::endl;


    // std::cout << IsDirectory("testdir") << std::endl;
    // std::cout << IsRegular("testfile") << std::endl;
    // std::cout << IsDirectory("testfile") << std::endl;
    // std::cout << IsRegular("testdir") << std::endl;
    // std::string ext;
    // while( std::cin >> ext)
    // {
    //     std::cout << ExMime(ext) << std::endl;
    // }
    // int status;
    // while( std::cin >> status)
    // {
    //     std::cout << StatusDesc(status) << std::endl;
    // }

    // std::string str = "/login?user  bite&passwd=C++";
    // std::string res = UrlEncode(str,true);
    // std::cout << res <<std::endl;
    // std::string res2 = UrlDecode(res,true);
    // std::cout << res2 <<std::endl;


    // test1;
    // // std::string str = "abc,,,,bcd,def,";
    // std::string str = "aaaaaaa,,,,";
    // std::vector<std::string> arry;
    // Split(str,",",&arry);
    // for(auto & s:arry)
    // {
    //     std::cout <<"[" <<s << "]" << std::endl;
    // }

    //test2
    // std::string buf;
    // int ret = ReadFile("./server.cc",buf);
    // if(ret == false) DBG_LOG("NNNN");
    // std::cout <<buf <<std::endl;

    //test3
    // ret = WriteFile("./tttt.cc",buf);
    
}










